package com.bodsite.rpc.spring.schema;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;

import com.bodsite.common.logger.Logger;
import com.bodsite.common.logger.LoggerFactory;
import com.bodsite.common.utils.StringUtils;
import com.bodsite.rpc.spring.schema.bean.Invok;
import com.bodsite.rpc.spring.schema.bean.Module;
import com.bodsite.rpc.spring.schema.bean.Service;
import com.bodsite.rpc.spring.schema.bean.Zookeeper;
import com.bodsite.rpc.thrift.client.ProxyService;
import com.github.pagehelper.util.StringUtil;

public class BodsiteBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
	private static final Logger logger = LoggerFactory.getLogger(BodsiteBeanDefinitionParser.class);
	private final Class<?> clazz;
	private Element element;
	private ParserContext parserContext;
	private BeanDefinitionBuilder bean;

	public BodsiteBeanDefinitionParser(Class<?> clazz) {
		this.clazz = clazz;
	}

	@Override
	protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
			throws BeanDefinitionStoreException {
		return resolveId();
	}

	@Override
	protected Class<?> getBeanClass(Element element) {
		return clazz;
	}

	@Override
	public void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder bean) {
		this.element = element;
		this.bean = bean;
		this.parserContext = parserContext;
		doParse();
	}

	private void doParse() {
		if (Module.class.equals(clazz)) {
			addPropertyValueSimple("name");//服务名-暂时每用
			addPropertyValueSimple("version");//版本
		} else if (Zookeeper.class.equals(clazz)) {
			addPropertyValueSimple("address");
			addPropertyValueSimple("group");
		} else if (Service.class.equals(clazz)) {
			addPropertyClass("proxyClass", "iface", "$Iface");//接口类
			addPropertyClass("proxyClass", "processor", "$Processor");//处理器
			addPropertyT("impl");//注入实现类
			addPropertyValueSimple("port", Integer.class);
			addPropertyValueSimple("selectorThreads", Integer.class);
			addPropertyValueSimple("workerThreads", Integer.class);
		} else if (Invok.class.equals(clazz)) {
			addPropertyClass("proxyClass", "iface", "$Iface");//接口类
			addPropertyClass("proxyClass", "client", "$Client");//客户端调用类
			BeanDefinition proxyBeanDefinition = registerBeanDefinition("proxyClass");//代理实现类
			addPropertyClass(proxyBeanDefinition, "proxyClass", "ifaceClass", "$Iface");//代理实现类-接口类

		}
	}

	private String resolveId() {
		String id = getAttribute("id");
		if (StringUtil.isEmpty(id)) {
			if (Service.class.equals(clazz) || Invok.class.equals(clazz)) {
				id = getAttribute("proxyClass");
			} else {
				id = clazz.getSimpleName();
			}
		}
		addPropertyValue("id", id);
		return id;
	}

	private void addPropertyT(String property) {
		String value = getAttribute(property);
		if (StringUtils.isNotBlank(value) && parserContext.getRegistry().containsBeanDefinition(value)) {
			// BeanDefinition refBean =
			// parserContext.getRegistry().getBeanDefinition(value);
			RuntimeBeanReference reference = new RuntimeBeanReference(value);
			addPropertyValue(property, reference);
		}
	}

	private BeanDefinition registerBeanDefinition(String property) {
		BeanDefinition beanDefinition = new GenericBeanDefinition();
		beanDefinition.setBeanClassName(ProxyService.class.getName());
		beanDefinition.setLazyInit(false);
		String id = resolveId();
		beanDefinition.getPropertyValues().addPropertyValue("id", resolveId());
		String beanName = id.substring(id.lastIndexOf(".") + 1);
		parserContext.getRegistry().registerBeanDefinition(StringUtils.captureName(beanName,1), beanDefinition);
		return beanDefinition;
	}

	private void addPropertyClass(BeanDefinition beanDefinition, String eProperty, String property, String inner) {
		try {
			Class<?> cls = Class.forName(getAttribute(eProperty) + inner);
			beanDefinition.getPropertyValues().addPropertyValue(property, cls);
		} catch (ClassNotFoundException e) {
			logger.error(e.getMessage(), e);
		}
	}

	private void addPropertyClass(String eProperty, String property, String inner) {
		try {
			Class<?> cls = Class.forName(getAttribute(eProperty) + inner);
			addPropertyValue(property, cls);
		} catch (ClassNotFoundException e) {
			logger.error(e.getMessage(), e);
		}
	}

	private void addPropertyValueSimple(String property) {
		addPropertyValueSimple(property, null);
	}

	private <T> void addPropertyValueSimple(String property, Class<T> t) {
		if (t == null) {
			bean.addPropertyValue(property, getAttribute(property));
		} else {
			bean.addPropertyValue(property, (T) (getAttribute(property)));
		}
	}

	private String getAttribute(String property) {
		return element.getAttribute(property);
	}

	private void addPropertyValue(String propertyName, Object propertyValue) {
		bean.addPropertyValue(propertyName, propertyValue);
	}
}
